package ModelAndController;
/*
 * A hálózati elemek osztály, felelős a huzalok és az egyéb elemek tárolásáért,
 *  valamint az ütemezési ciklus első lépésének - a jelgenerátorok, 
 *  kapcsolók állapotfrissítésének - elindításáért.
 */
//Exception 140 es 159 kozott
public class CircuitElements {
	//Bemeneti kapukat tartalmazó tömb.
	private Gate[] inputGate;
	//Kimeneti kapukat tartalmazó tömb.
	private Gate[] outputGate;
	////Kompozit elemeket tartalmazó tömb.
	private Composite[] composites;
	//Jelgenerátorokat tartalmazó tömb.
	private SignalGenerator[] signalGenerators;
	//Kapcsolókat tartalmazó tömb.
	private Switch[] switches;
	//Kijelzőket tartalmazó tömb.
	private Display[] displays;
	//Oszcilloszkópokat tartalmazó tömb.
	private Scope[] scopes;
	//Építőelemeket tartalmazó tömb.
	private Element[] elements;
	//Huzalokat tartalmazó tömb.
	private Wire[] wires;
	//az osztály üzeneteit tartalmazó tömb
	private String buffer;
	//a tartalmazott elemek száma
	private int nbOfCircuitElements;
	//a tabulátor karaktert tároló string
	private String tab;
	//konstruktor
	public CircuitElements(int nbOfCircuit, Gate[] copyInput, Gate[] copyOutput, SignalGenerator[] copySignal, Switch[] copySwitch, Composite[] copyComposites, Display[] copyDisplays, Scope[] copyScopes, Element[] copyElements, Wire[] copyWires){
		nbOfCircuitElements = nbOfCircuit;
		tab = "     ";
		inputGate = copyInput; outputGate = copyOutput;
		signalGenerators = copySignal; switches = copySwitch;
		composites = copyComposites;
		displays = copyDisplays; scopes = copyScopes;
		elements = copyElements; wires = copyWires;
	}
	//a tartalmazott elemek számát adja vissza
	public int getNbOfCircuitElements(){
		return nbOfCircuitElements;
	}
	public void checkCircuitElements() throws Exception{
		for(int act=0; act<elements.length; act++)
		try{
			elements[act].check();
		}catch(Exception e){
			throw new Exception(e.getMessage()+" ElementIndex="+act);
		}
		for(int act=0; act<wires.length; act++)
			try{
				wires[act].check();
			}catch(Exception e){
				throw new Exception(e.getMessage()+" WireIndex="+act);
			}
	}
	//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*
	//Switch
	//a tartalmazott kapcsolók számát adja vissza
	public int getNbOfSwitches(){
		if(switches != null)
			return switches.length;
		else
			return 0;
	}
	//az aktuális kapcsoló értékét adja vissza
	public int getValueOfActualSwitch(int actSwitch){
		if(switches != null)
			if(0<=actSwitch && actSwitch<switches.length)
				return switches[actSwitch].getState(0);
		return 0;
	}
	//az aktuális kapcsoló értékét állítja be
	public void setValueOfActualSwitch(int actSwitch){
		if(switches != null)
			if(0<=actSwitch && actSwitch<switches.length)
				switches[actSwitch].setValue();
	}
	//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*
	//SignalGenerator
	//a jelgenerátorok számát adja vissza
	public int getNbOfSignalGenerators(){
		if(signalGenerators != null)
			return signalGenerators.length;
		else
			return 0;
	}
	//az aktuális jelgenerátor értékét állítja be
	public void setValuesOfActualSignalGenerator(int actSignalG, int[] values){
		if(signalGenerators != null)
			if(0<=actSignalG && actSignalG<signalGenerators.length)
				signalGenerators[actSignalG].setStateArray(values);
	}
	//az aktuális jelgenerátor értékét adja vissza
	public int[] getValuesOfActualSignalGenerator(int actSignalG){
		if(signalGenerators != null )
			if(0<=actSignalG && actSignalG<signalGenerators.length)
				return signalGenerators[actSignalG].getStateArray();
		return null;	
	}
	public int getValueOfActualSignalGenerator(int actSignalG){
		if(signalGenerators != null){
			if(0<=actSignalG && actSignalG<signalGenerators.length)
				return signalGenerators[actSignalG].getState(0);
		}
		return -1;
	}
	
	/*
	 * Az ütemezési ciklus első lépéseként beállítja a 
	 * jelgenerátor soron következő belső állapotát.
	 */
	public void setNextStateAtSignalGenerators(){
		if(signalGenerators != null)
			for(int act=0; act<signalGenerators.length; act++)
				signalGenerators[act].setNextState();
	}
	/*
	 * Jelzi a jelgenerátoroknak és a kapcsolóknak,
	 * hogy a következő ütemezési körben 
	 * végezzen isUpdateSucces() műveletet.
	 */
	public void signalGeneratorsAndSwitchesUpdateToSchedule(){
		if(signalGenerators != null)
			for(int act=0; act<signalGenerators.length; act++)
				signalGenerators[act].shouldUpdate();
		if(switches != null)
			for(int act=0; act<switches.length; act++)
				switches[act].shouldUpdate();
	}
	//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*
	//Scope
	////a scope-ok számát adja vissza
	public int getNbOfScopes(){
		if(scopes != null)
			return scopes.length;
		else
			return 0;
	}
	//a scope értékét adja vissza
	public int[] getValuesOfActualScope(int actScope){
		if(scopes != null)
			if(0<=actScope && actScope<scopes.length)
				return scopes[actScope].getState();
		return null;
	}
	//a scope deltáját adja vissza
	public int[] getDeltaOfActualScope(int actScope){
		if(scopes != null)
			if(0<=actScope && actScope<scopes.length)
				return scopes[actScope].getDelta();
		return null;
	}
	//a scope deltáját törli
	public void clearScopesDelta(){
		if(scopes != null)
			for(int act=0; act<scopes.length; act++)
				scopes[act].clearDelta();
	}
	public void finalizeScopes(){
		if(scopes != null)
			for(int act=0; act<scopes.length; act++)
				scopes[act].finalizeSchedule();
	}
	//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*
	//Display
	//a kijelzők számát adja vissza
	public int getNbOfDisplays(){
		if(displays != null)
			return displays.length;
		else
			return 0;
	}
	//az aktuális kijelző értékét adja vissza
	public int getValueOfActualDisplay(int actDisplay){
		if(displays != null)
			if(0<=actDisplay && actDisplay<displays.length)
				return displays[actDisplay].getState(0);
		return -1;
	}
	//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*
	//InputGate
	//a bemeneti kapuk számát állítja be
	public void setInputGateNumber(int nbOfInputGates) throws Exception{
		if( nbOfInputGates < 0 )
			throw new Exception("140");
	}
	
	public void setActualWireToInputGate(int nbOfActInputGate, Wire act) throws Exception{
		if( inputGate == null)
			throw new Exception("141");
		if( (nbOfActInputGate < 0) || (inputGate.length <= nbOfActInputGate) )
			throw new Exception("142");		
		inputGate[nbOfActInputGate].setActualInputWire(0, act);
	}
	
	public boolean checkIfAnyInputGateShouldUpdate(){
		if( inputGate == null )
			return false;
		
		for(int act=0; act<inputGate.length; act++)
			if( inputGate[act].shouldUpdate )
					return true;
		
		return false;
	}
	
	public Gate getReferenceToActualInputGate(int nbOfActualGate) throws Exception{
		if( inputGate == null )
			throw new Exception("149");
		
		if( nbOfActualGate<0 || inputGate.length <= nbOfActualGate)
			throw new Exception("150 "+nbOfActualGate);
		
		return inputGate[nbOfActualGate];
	}
	
	//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*
	//OutputGate
	
	public void setOutputGateNumber(int nbOfOutputGates) throws Exception{
		if(nbOfOutputGates < 0)
			throw new Exception("143");
	}
	
	public int getOutputGateNumber(){
		if(outputGate == null)
			return 0;
		return outputGate.length;
	}
	
	public void setOutputGateWireNumbers(int nbOfActOutputGate, int nbOfOutputWireOnAct) throws Exception{
		if(outputGate == null)
			throw new Exception("145");
		if( (nbOfActOutputGate < 0) || (outputGate.length <= nbOfActOutputGate) )
			throw new Exception("144");
		
		outputGate[nbOfActOutputGate].setOutputNumbers(nbOfOutputWireOnAct);
	}
	
	public void setWireToActualOutputOnOutputGate(int nbOfActOutputGate, int nbOfOutputWireAct, Wire act) throws Exception{
		if(outputGate == null)
			throw new Exception("145");
		if( (nbOfActOutputGate < 0) || ( outputGate.length <= nbOfActOutputGate) )
			throw new Exception("146");
		
		outputGate[nbOfActOutputGate].setActualOutputWire(nbOfOutputWireAct, act);
	}
	
	public int getActualOutputGate(int nbOfActOutputGate) throws Exception{
		if(outputGate == null)
			throw new Exception("145");
		if( (nbOfActOutputGate < 0) || ( outputGate.length <= nbOfActOutputGate) )
			throw new Exception("147");
		
		return outputGate[nbOfActOutputGate].getState(nbOfActOutputGate);
	}
	
	public Gate getReferenceToActualOutputGate(int nbOfOutputGate) throws Exception{
		if(outputGate == null)
			throw new Exception("145");
		if( (nbOfOutputGate < 0) || (outputGate.length <= nbOfOutputGate) )
			throw new Exception("147");
		
		return outputGate[nbOfOutputGate];
	}
	
	//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*
	//Composite
	
	public void setCompositesIfShouldWriteDetails(int[] shouldWriteOutput) throws Exception{
		
		if( shouldWriteOutput == null || composites == null )
			return;
		if( shouldWriteOutput.length == 1 && shouldWriteOutput[0] == -1  ){
			for(int act=0; act<composites.length; act++)
				composites[act].setIfShouldListDetails(true);
			return;
		}
			
		for(int act=0; act<shouldWriteOutput.length; act++){
			if( shouldWriteOutput[act] < 0 || composites.length <= shouldWriteOutput[act])
				throw new Exception("149");
			composites[act].setIfShouldListDetails(true);
		}		
	}
	
	public void allCompositeStopListingDetails(){
		if( composites == null)
			return;
		
		for(int act=0; act<composites.length; act++)
			composites[act].stopListingDetails();
	}
	
	//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*//*
	//Update
	/*
	 * Minden építőelemnek (huzalok kivételével) lehetőséget ad az ütemezésre. 
	 * Ha valamelyik építőelemnek változott az állapota, 
	 * akkor azt a visszatérési érték jelzi.
	 */
	public boolean updateAllElements() throws Exception{
		boolean retValue = false;
		try{
			buffer = tab+"Elements: ";
		
			for(int act=0; act<elements.length; act++){
				if(elements[act].isUpdateSuccess())
					retValue = true;
				buffer = buffer.concat(elements[act].getBuffer()+" ");
			}
		}catch(Exception e){
			if( e.getMessage().startsWith("260") )
				throw new Exception("260 "+buffer+" "+e.getMessage().replaceFirst("260", ""));
			throw e;
		}
		return retValue;
	}
	/*
	 * Lehetőséget ad minden huzalnak, hogy isUpdateSucces() művelettel éljen. 
	 * Ha valamelyik huzal belső értéke változott, 
	 * akkor azt jelzi a visszatérési értékkel.
	 */
	public boolean updateAllWires() throws Exception{
		boolean retValue = false;
		buffer = tab+"Wires: ";
		
		for(int act=0; act<wires.length; act++){
			if(wires[act].isUpdateSuccess())
			retValue = true;
			buffer = buffer.concat(wires[act].getBuffer()+" ");
		}
		
		return retValue;
	}

	/**
	 * @return the buffer
	 */
	public String getBuffer() {
		return buffer;
	}

	/**
	 * @param buffer the buffer to set
	 */
	public void setBuffer(String buffer) {
		this.buffer = buffer;
	}
	
}
